﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace H.QuickDoes
{
    /// <summary>
    /// 表示一个快速操作,主要是提供自动状态机
    /// </summary>
    /// <typeparam name="C">上下文的类型,此类型关系到可以在上下文共享的数据的类型</typeparam>
    public interface IQuickDo<C> where C : IQDContext
    {
        /// <summary>
        /// 获取上下文信息,以便读写上下文信息中的内容
        /// </summary>
        C Context { get; }

        /// <summary>
        /// 用于停止执行的令牌
        /// </summary>
        CancellationToken CT { get; set; }

        /// <summary>
        /// 存储用于产生失败等待的时间的函数
        /// 第一个参数是已经失败的次数(如果是固定延时时间,则可以忽略)
        /// 第二个参数用于取消延时
        /// 返回值是真实延时的时长
        /// 默认值是500~1000的延时
        /// </summary>
        Func<int, int> FailedDelayFunc { get; set; }

        /// <summary>
        /// 设置一个快速操作
        /// </summary>
        /// <param name="actionID">为快速操作设置一个ID,以便在其他地方引用它</param>
        /// <param name="action">需要进行的操作,返回值可以为bool,int,int[]</param>
        /// <param name="retry">尝试的次数,在指定的次数内如果能够执行成功,那么还是执行成功的</param>
        /// <param name="rollbackID">当<paramref name="action"/>连续返回<paramref name="retry"/>次false时,跳转到的状态ID,
        /// 如果设置为null,则当<paramref name="action"/>连续返回<paramref name="retry"/>次false时,从DoAction返回false,
        /// 注意: 如果设置为null,则表示Action可能从此Action结束</param>
        /// <param name="retryDelay">指定一个用于计算下一次重试前等待时间的函数,函数参数为当前失败的次数,从1开始</param>
        /// <returns>返回新创建的Action</returns>
        void SetAction(int actionID, Func<IQuickDo<C>, dynamic> action, int retry, int? rollbackID, Func<int, int> retryDelay = null);

        /// <summary>
        /// 手动执行某个Action
        /// </summary>
        /// <param name="id">需要被执行的Action的ID</param>
        /// <param name="enableTransfer">是否进行状态转移(如果设置为false,则将Action当做一次调用来使用,不会根据状态跳转到下一个状态)</param>
        /// <returns>返回是否成功</returns>
        bool DoAction(int id, bool enableTransfer = true);

        /// <summary>
        /// 执行延时(提供给action内部使用)
        /// </summary>
        /// <param name="delayMs">希望延时的时间(以毫秒计)</param>
        /// <returns></returns>
        int Delay(int delayMs);

        /// <summary>
        /// 执行延时(提供给action内部使用)
        /// </summary>
        /// <param name="minDelayMs">希望延时的最短时间(以毫秒计)</param>
        /// <param name="maxDelayMs">希望延时的最长时间(以毫秒计)</param>
        /// <returns></returns>
        int Delay(int minDelayMs, int maxDelayMs);
    }
}
